package cn.spikego.advicelite.client.core.event.impl

import cn.spikego.advicelite.client.core.event.util.EventCaller
import cn.spikego.advicelite.client.core.event.util.EventInitializer
import cn.spikego.advicelite.client.eventapi.events.Event
import cn.spikego.advicelite.client.mapping.MappingManager
import net.bytebuddy.ByteBuddy
import net.bytebuddy.asm.Advice
import net.bytebuddy.description.method.MethodDescription
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy
import net.bytebuddy.dynamic.scaffold.TypeValidation
import net.bytebuddy.implementation.bind.annotation.RuntimeType
import net.bytebuddy.matcher.ElementMatcher
import net.bytebuddy.matcher.ElementMatchers.named
import net.bytebuddy.matcher.ElementMatchers.takesArgument

class Render2DEvent() : Event, EventInitializer {

    private var poseStack: Any? = null
    private var partialTicks: Float = 0f

    constructor(poseStack: Any, partialTicks: Float) : this() {
        this.poseStack = poseStack
        this.partialTicks = partialTicks
    }

    fun getPartialTicks(): Float = partialTicks

    fun getPoseStack(): Any? = poseStack

    companion object {
        @JvmStatic
        @RuntimeType
        @Advice.OnMethodEnter(skipOn = Boolean::class)
        fun onRender(@RuntimeType obj: Any, partialTicks: Float): Boolean? {
            return if (EventCaller.callEvent("onRender", obj, partialTicks)) true else null
        }
    }

    @Throws(Exception::class)
    override fun initialize(byteBuddy: ByteBuddy, loader: ClassLoader, mappingManager: MappingManager) {
        val clazz = loader.loadClass(mappingManager.translateClassName("net.minecraft.client.gui.Gui"))
        val method = mappingManager.translateMethodName(
            "net.minecraft.client.gui.Gui",
            "render(Lcom/mojang/blaze3d/vertex/PoseStack;F)V"
        )
        byteBuddy.with(TypeValidation.DISABLED)
            .redefine(clazz)
            .visit(
                Advice.to(this::class.java)
                    .withExceptionPrinting()
                    .on(
                        ((named<MethodDescription>(method)
                            .and(takesArgument<MethodDescription>(1, java.lang.Float.TYPE)))
                                as ElementMatcher<in MethodDescription>)
                    )
            )
            .make().load(loader, ClassReloadingStrategy.fromInstalledAgent())
    }
}